#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include<time.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdbool.h>
#include <limits.h>
#include <stdarg.h>
#include <syslog.h>
#include "ModuleA.h"
#define MAX_PATH_LEN (256) 
#define THREADS_COUNT 1
#define THREADS_BUFF_SIZE 1*1024
void LOG(char *a)
{
	char buffer[1024] = {0};
	time_t now;
	time(&now);
	struct tm *local;
	local = localtime(&now);
	sprintf(buffer,"%04d-%02d-%02d %02d:%02d:%02d 执行操作%s\n", local->tm_year+1900, local->tm_mon,local->tm_mday, local->tm_hour, local->tm_min, local->tm_sec,a);
	FILE* file = fopen("testResut.log","a+");
	fwrite(buffer,1,strlen(buffer),file);
	fclose(file);
}
///获取文件大小
size_t get_filesize(int fd)
{
    struct stat st;
    fstat(fd,&st);
    return st.st_size;
}
int is_dir(char* path){//判断是否是目录
	struct stat st;
	stat(path,&st);
	if(S_ISDIR(st.st_mode)){
		return 1;
	}
	else{
		return 0;
	}
}
/*字符串处理函数*/
int endwith(char* s,char c){//用于判断字符串结尾是否为“/”
	if(s[strlen(s)-1]==c){
		return 1;
	}
	else{
		return 0;
	}
}
char* str_contact(char* str1,char* str2){//字符串连接
	char* result;
	result=(char*)malloc(strlen(str1)+strlen(str2)+1);//str1的长度+str2的长度+\0;
	if(!result){//如果内存动态分配失败
		printf("字符串连接时，内存动态分配失败\n");
		exit(1);
	}
	strcat(result,str1);
	strcat(result,str2);//字符串拼接
	return result;
}
void *thread_copy_fn(void *arg);
void Copy(char *spathname,char *tpathname)
{
    ///打开文件
    struct stat s; 
    int infd = open(spathname,O_RDONLY);
    int outfd = open(tpathname,O_CREAT|O_WRONLY,0777);
    // 0644也就是-文件所有者有读写权限，组有读权限，其他用户有读权限
    if(infd == -1|| -1 ==outfd)
    {
	printf("infd=%d\n",infd);
	printf("outfd=%d\n",outfd);
        printf("error while open file \n");
    }
    size_t file_size = get_filesize(infd);
 
    size_t thread_size = THREADS_COUNT;
    struct thread_block *blocks = (struct thread_block *)
        malloc(sizeof(struct thread_block )* thread_size);
    size_t percent = file_size / thread_size;
    int i = 0;
    //init-thread-block
    for(; i < thread_size;++i)
    {
        blocks[i].infd = infd;
        blocks[i].outfd = outfd;
        blocks[i].start = i * percent;
        blocks[i].end = blocks[i].start + percent;
    }
    //the last thread
    blocks[i].end = file_size;
    pthread_t ptid[thread_size];    
    ///创建线程
    for(i = 0 ; i < thread_size; ++i)
    {
        pthread_create(&ptid[i],NULL,thread_copy_fn,&(blocks[i]));
    }
    ///线程Join
    for(i = 0 ; i < thread_size; ++i)
   {
        pthread_join(ptid[i],NULL);
    }
    ///释放资源
    free(blocks);
    fstat(infd,&s);
    chown(tpathname,s.st_uid,s.st_gid);
    chmod(tpathname,s.st_mode);
    close(infd);
    close(outfd);
}
 
void *thread_copy_fn(void *arg)
{
    struct thread_block *block = (struct thread_block *)arg;
    char buf[THREADS_BUFF_SIZE];    
    size_t count = block->start;
    int ret;
    ret = lseek(block->infd,block->start,SEEK_SET);
    ret = lseek(block->outfd,block->start,SEEK_SET);
    int bytes_read;
    int bytes_write;
    while(count < block->end)
    {
        bytes_read = read(block->infd,buf,sizeof(buf));
        if(bytes_read >0)
        {
            count += bytes_read;
 
            //read（）返回-1，同时errno为EINTR，表示读的过程中遇到了中断
            if((bytes_read == -1)&&(errno !=EINTR))
                    break;
            char *ptr_write = buf;
            while((bytes_write = write(block->outfd,ptr_write,bytes_read))!=0)
            {
                //write（）会返回-1，同时errno为EINTR，表示在写的过程中遇到了中断
                if((bytes_write == -1)&&(errno!=EINTR))
                    break;
                if(bytes_write == bytes_read)
                    break;
                else if(bytes_write > 0)
                {
                    ptr_write += bytes_write;
                    bytes_read -= bytes_write;
                }
            }//end-write;
            ///error while write
            if(bytes_write == -1)
                break;
            
        }
    }
    pthread_exit(NULL); 
}
void copy_folder(char* source_path,char *destination_path){//复制文件夹
	if(!opendir(destination_path)){
		if (mkdir(destination_path,0777))//如果不存在就用mkdir函数来创建
		{
		    printf("创建文件夹失败！");
		}
	}
	char* path=(char*)malloc(512);//相当于其它语言的String path=""，纯C环境下的字符串必须自己管理大小，这里为path直接申请512的位置的空间，用于目录的拼接
	path=str_contact(path,source_path);//这三句，相当于path=source_path
	struct dirent* filename;
	DIR* dp=opendir(path);//用DIR指针指向这个文件夹
	while((filename=readdir(dp))!=NULL){//遍历DIR指针指向的文件夹，也就是文件数组。
		if(path!=NULL){
		memset(path,0,sizeof(path));
		}
		path=str_contact(path,source_path);
		//如果source_path,destination_path以路径分隔符结尾，那么source_path/,destination_path/直接作路径即可 
		//否则要在source_path,destination_path后面补个路径分隔符再加文件名，谁知道你传递过来的参数是f:/a还是f:/a/啊？
		char *file_source_path;
		file_source_path=(char*)malloc(512);
		if(!endwith(source_path,'/')){
			file_source_path=str_contact(file_source_path,source_path);
			file_source_path=str_contact(source_path,"/");
		}
		else{
			file_source_path=str_contact(file_source_path,source_path);
		}
		char *file_destination_path;
		file_destination_path=(char*)malloc(512);
		if(!endwith(destination_path,'/')){
			file_destination_path=str_contact(file_destination_path,destination_path);
			file_destination_path=str_contact(destination_path,"/");
		}
		else{
			file_destination_path=str_contact(file_destination_path,destination_path);
		}
		//取文件名与当前文件夹拼接成一个完整的路径
		file_source_path=str_contact(file_source_path,filename->d_name);
		file_destination_path=str_contact(file_destination_path,filename->d_name);
		if(is_dir(file_source_path)){//如果是目录
			if(!endwith(file_source_path,'.')){//同时并不以.结尾，因为Linux在所有文件夹都有一个.文件夹用于连接上一级目录，必须剔除，否则进行递归的话，后果无法相像
				copy_folder(file_source_path,file_destination_path);//进行递归调用，相当于进入这个文件夹进行复制～
			}		
		}
		else{
			Copy(file_source_path,file_destination_path);//否则按照单一文件的复制方法进行复制。
		}
	}	
}
void remove_dir(const char *dir)
{
    char cur_dir[] = ".";
    char up_dir[] = "..";
    char dir_name[128];
    DIR *dirp;
    struct dirent *dp;
    struct stat dir_stat;
    // 参数传递进来的目录不存在，直接返回
    if ( 0 != access(dir, F_OK) ) {
        return 0;
    }

    // 获取目录属性失败，返回错误
    if ( 0 > stat(dir, &dir_stat) ) {
        perror("get directory stat error");
        return -1;
    }

    if ( S_ISREG(dir_stat.st_mode) ) {  // 普通文件直接删除
        remove(dir);
    } else if ( S_ISDIR(dir_stat.st_mode) ) {   // 目录文件，递归删除目录中内容
        dirp = opendir(dir);
        while ( (dp=readdir(dirp)) != NULL ) {
            // 忽略 . 和 ..
            if ( (0 == strcmp(cur_dir, dp->d_name)) || (0 == strcmp(up_dir, dp->d_name)) ) {
                continue;
            }

            sprintf(dir_name, "%s/%s", dir, dp->d_name);
            remove_dir(dir_name);   // 递归调用
        }
        closedir(dirp);

        rmdir(dir);     // 删除空目录
    } else {
        perror("unknow file type!");    
    }
}
void trave_dira(char* path,char* path2) {
	
	DIR *d = NULL,*z=NULL;
    struct dirent *dp = NULL,*dt=NULL; /* readdir函数的返回值就存放在这个结构体中 */
    struct stat st,qt;    
    char p[MAX_PATH_LEN] = {0};
    char t[MAX_PATH_LEN] = {0};
    char q[MAX_PATH_LEN] = {0};
    if(stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) {
        printf("invalid path: %s\n", path);
        return;
    }
 
    if(!(d = opendir(path))) {
        printf("opendir[%s] error: %m\n", path);
        return;
    }
        if(stat(path2, &qt) < 0 || !S_ISDIR(qt.st_mode)) {
        printf("invalid path: %s\n", path2);
        return;
    }
 
    if(!(z = opendir(path2))) {
        printf("opendir[%s] error: %m\n", path2);
        return;
    }
    while((dp= readdir(d)) != NULL) {
        /* 把当前目录.，上一级目录..及隐藏文件都去掉，避免死循环遍历目录 */
        if((!strncmp(dp->d_name, ".", 1))|| (!strncmp(dp->d_name, "..", 2)))
            continue;
 
        snprintf(p, sizeof(p) - 1, "%s/%s", path,dp->d_name);
        stat(p, &st);
        

     while((dt = readdir(z)) != NULL) {
        /* 把当前目录.，上一级目录..及隐藏文件都去掉，避免死循环遍历目录 */
        snprintf(t, sizeof(t) - 1, "%s/%s", path2, dt->d_name);
        stat(t,&qt);
	snprintf(q, sizeof(q) - 1, "%s/%s", path2, dp->d_name);
	if((S_ISDIR(st.st_mode)&&S_ISDIR(qt.st_mode))&&strcmp(dp->d_name,dt->d_name)==0)
	{
		trave_dira(p,t);
		
	}
	else if((!S_ISDIR(st.st_mode)&&!S_ISDIR(qt.st_mode))&&strcmp(dp->d_name,dt->d_name)==0&&difftime(st.st_mtime,qt.st_mtime)!=0)
        {
                FILE *file;
                file = fopen(t,"w");
                fclose(file);
                Copy(p,t);
        }	
	if((access(q,F_OK)==-1))
        {
                  if((S_ISDIR(st.st_mode)))
                {
                        mkdir(q,0777);
                       	copy_folder(p,q);
                }
                if(!(S_ISDIR(st.st_mode)))
                {
                        FILE *file;
                        if((access(q,F_OK))!=-1)
                        {
                                continue;
                        }else
                        {
                        file=fopen(q,"w+");
                        }
                        fclose(file);
                        Copy(p,q);
                }

        }
	}
	 closedir(z);
        z = opendir(path2);
    }
}
void trave_dir(char* path,char* path2) {
	
	DIR *d = NULL,*z=NULL;
    struct dirent *dp = NULL,*dt=NULL; /* readdir函数的返回值就存放在这个结构体中 */
    struct stat st,qt;    
    char p[MAX_PATH_LEN] = {0};
    char t[MAX_PATH_LEN] = {0};
    char q[MAX_PATH_LEN] = {0};
    if(stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) {
        printf("invalid path: %s\n", path);
        return;
    }
 
    if(!(d = opendir(path))) {
        printf("opendir[%s] error: %m\n", path);
        return;
    }
        if(stat(path2, &qt) < 0 || !S_ISDIR(qt.st_mode)) {
        printf("invalid path: %s\n", path2);
        return;
    }
 
    if(!(z = opendir(path2))) {
        printf("opendir[%s] error: %m\n", path2);
        return;
    }
    while((dp= readdir(d)) != NULL) {
        /* 把当前目录.，上一级目录..及隐藏文件都去掉，避免死循环遍历目录 */
        if((!strncmp(dp->d_name, ".", 1))|| (!strncmp(dp->d_name, "..", 2)))
            continue;
 
        snprintf(p, sizeof(p) - 1, "%s/%s", path,dp->d_name);
        stat(p, &st);
        

     while((dt = readdir(z)) != NULL) {
        /* 把当前目录.，上一级目录..及隐藏文件都去掉，避免死循环遍历目录 */
        snprintf(t, sizeof(t) - 1, "%s/%s", path2, dt->d_name);
        stat(t,&qt);
	snprintf(q, sizeof(q) - 1, "%s/%s", path2, dp->d_name);
	if((S_ISDIR(st.st_mode)&&S_ISDIR(qt.st_mode))&&strcmp(dp->d_name,dt->d_name)==0)
	{
		trave_dir(p,t);
		
	}
	else if((!S_ISDIR(st.st_mode)&&!S_ISDIR(qt.st_mode))&&strcmp(dp->d_name,dt->d_name)==0&&difftime(st.st_mtime,qt.st_mtime)>0)
        {
                FILE *file;
                file = fopen(t,"w");
                fclose(file);
                Copy(p,t);
        }
	else if((!S_ISDIR(st.st_mode)&&!S_ISDIR(qt.st_mode))&&strcmp(dp->d_name,dt->d_name)==0&&difftime(st.st_mtime,qt.st_mtime)<0)
        {
                FILE *file;
                file = fopen(p,"w");
                fclose(file);
                Copy(t,p);
        }
	
	if((access(q,F_OK)==-1))
        {
                  if((S_ISDIR(st.st_mode)))
                {
                        mkdir(q,0777);
                       	copy_folder(p,q);
                }
                if(!(S_ISDIR(st.st_mode)))
                {
                        FILE *file;
                        if((access(q,F_OK))!=-1)
                        {
                                continue;
                        }else
                        {
                        file=fopen(q,"w+");
                        }
                        fclose(file);
                        Copy(p,q);
                }

        }
	}
	 closedir(z);
        z = opendir(path2);
    }
}
void trave_diraz(char* path,char* path2) {
	DIR *d = NULL,*z=NULL;
    struct dirent *dp = NULL,*dt=NULL; /* readdir函数的返回值就存放在这个结构体中 */
    struct stat st,qt;    
    char p[MAX_PATH_LEN] = {0};
    char t[MAX_PATH_LEN] = {0};
    char q[MAX_PATH_LEN] = {0};
    if(stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) {
        printf("invalid path: %s\n", path);
        return;
    }
 
    if(!(d = opendir(path))) {
        printf("opendir[%s] error: %m\n", path);
        return;
    }
        if(stat(path2, &qt) < 0 || !S_ISDIR(qt.st_mode)) {
        printf("invalid path: %s\n", path2);
        return;
    }
 
    if(!(z = opendir(path2))) {
        printf("opendir[%s] error: %m\n", path2);
        return;
    }
    while((dp= readdir(d)) != NULL) {
        /* 把当前目录.，上一级目录..及隐藏文件都去掉，避免死循环遍历目录 */
        if((!strncmp(dp->d_name, ".", 1)) || (!strncmp(dp->d_name, "..", 2)))
            continue;
 
        snprintf(p, sizeof(p) - 1, "%s/%s", path,dp->d_name);
        stat(p, &st);
     while((dt = readdir(z)) != NULL) {
        snprintf(t, sizeof(t) - 1, "%s/%s", path2, dt->d_name);
        stat(t,&qt);
	snprintf(q, sizeof(q) - 1, "%s/%s", path2, dp->d_name);
	 if((S_ISDIR(st.st_mode)&&S_ISDIR(qt.st_mode))&&strcmp(dp->d_name,dt->d_name)==0)
        {
                trave_diraz(p,t);

        }
	if((access(q,F_OK)==-1))
        {
                  if((S_ISDIR(st.st_mode)))
                {
                        remove_dir(p);
                }
                if(!(S_ISDIR(st.st_mode)))
                {
                        remove(p);
                }

        }
	}
	 closedir(z);
        z = opendir(path2);
    }
}
void ProgressBar()
{
	char arr[102] = {'\0'};
	char *imag = "|/-\\";
	int n = 100, i = 0;
	while (i <= n)
	{
		arr[i] = '=';
		printf("[%-100s][%d%%][%c]\r", arr, i, imag[i % 4]);
		fflush(stdout);
		usleep(1000);
		i++;
	}
	printf("\n");
}
